﻿using System;
using System.Web;
using System.Web.Mvc;
using Icms.Core;
using Icms.Core.Model;
using Icms.Core.Service;
using Icms.WebUI.Builder;
using Icms.WebUI.Dto;
using Omu.ValueInjecter;

namespace Icms.WebUI.Controllers
{
    /// <summary>
    /// generic crud controller for entities where there is difference between the edit and create view
    /// </summary>
    /// <typeparam name="TEntity"> the entity</typeparam>
    /// <typeparam name="TCreateInput">create viewmodel</typeparam>
    /// <typeparam name="TEditInput">edit viewmodel</typeparam>
    public class Crudere<TEntity, TCreateInput, TEditInput> : BaseController
        where TCreateInput : new()
        where TEditInput : Input, new()
        where TEntity : Entity, new()
    {
        protected readonly ICrudService<TEntity> s;
        protected readonly IMapper<TEntity, TCreateInput> v;
        protected readonly IMapper<TEntity, TEditInput> ve;

        protected virtual string EditView
        {
            get { return "edit"; }
        }

        public Crudere(ICrudService<TEntity> s, IMapper<TEntity, TCreateInput> v, IMapper<TEntity, TEditInput> ve)
        {
            this.s = s;
            this.v = v;
            this.ve = ve;
        }

        public virtual ActionResult Index()
        {
            return View("cruds");
        }
        
        public virtual ActionResult Row(Guid id)
        {
            return View("rows", new[] { s.Get(id) });
        }

        public virtual ActionResult Create()
        {
            var e = new TEntity();
            e.InjectFrom<RequestToClass>(Request);
            
            return View(BeforeCreate(v.MapToInput(e)));
        }

        protected virtual TCreateInput BeforeCreate(TCreateInput o)
        {
            return o;
        }

        [HttpPost]
        public virtual ActionResult Create(TCreateInput o)
        {
            if (!ModelState.IsValid)
                return View(v.RemapInput(o));
            return Json(new { Id = Creation(v.MapToEntity(o)) });
        }

        public virtual Guid Creation(TEntity e)
        {
            return s.Create(e);
        }

        public virtual ActionResult Edit(Guid id, string msg=null)
        {
            var o = s.Get(id);
            if (o == null) throw new IcmsException("this entity doesn't exist anymore");
            ViewBag.Msg = msg;
            return View(EditView, ve.MapToInput(o));
        }

        [HttpPost]
        public virtual ActionResult Edit(TEditInput input)
        {
            try
            {
                if (!ModelState.IsValid)
                    return View(EditView, ve.RemapInput(input, input.Id));
                s.Save(ve.MapToEntity(input, input.Id));
            }
            catch (IcmsException ex)
            {
                return Content(ex.Message);
            }
            return Json(new { input.Id });
        }

        [HttpPost]
        public ActionResult Delete(Guid id)
        {
            s.Delete(id);
            return Json(new { Id = id });
        }
    }

    public class RequestToClass : KnownSourceValueInjection<HttpRequestBase>
    {
        protected override void Inject(HttpRequestBase source, object target)
        {
            var props = target.GetProps();
            for (var i = 0; i < props.Count; i++)
            {
                var prop = props[i];
                if (source[prop.Name] != null)
                {
                    if(prop.PropertyType==typeof(Guid))
                    prop.SetValue(target, new Guid(source[prop.Name]));
                    
                }
            }
        }
    }
}